#ifndef SKYROAD_BIN_SIZE_CALCULATOR_H_
#define SKYROAD_BIN_SIZE_CALCULATOR_H_

#include <string>
#include <vector>
#include <boost/array.hpp>
#include <skyroad/archive/nvp.hpp>
#include <skyroad/detail/config.hpp>


class SKYROAD_DECL bin_size_calculator
{
public:
    bin_size_calculator(int version) : m_value(0), m_version(version)
    {
    }

    std::size_t value()
    { 
        return m_value;
    }

    int version()
    {
        return m_version;
    }

    bin_size_calculator& operator+=(std::size_t size) 
    {
        m_value += size;
        return *this;
    }

private:
    std::size_t m_value;
    int m_version;
};


template <typename T>
bin_size_calculator& operator &(bin_size_calculator& calc, std::vector<T>& value)
{
    calc += 2;
    for (int i = 0; i < value.size(); i++)
    {
        serialize(calc, value[i], calc.version());
    }
    return calc;
}

template <typename T, std::size_t N>
bin_size_calculator& operator &(bin_size_calculator& calc, const boost::array<T,N>& value)
{
    calc += value.size()*sizeof(T);
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, const float& value)
{
    calc += sizeof(float);
    return calc;
}

template <class T>
bin_size_calculator& operator &(bin_size_calculator& calc, const T& item)
{
    calc += item.size();
    return calc;
}

template <class T>
bin_size_calculator& operator &(bin_size_calculator& calc, const nvp<T>& item)
{
    calc & *item.second;
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, const std::string& value)
{
    calc += value.size() + 1;
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, const std::wstring& value)
{
    calc += value.size()*2 + 2;
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, unsigned char value)
{
    calc += 1;
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, unsigned short value)
{
    calc += 2;
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, unsigned long value)
{
    calc += sizeof(value);;
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, int value)
{
    calc += sizeof(value);
    return calc;
}

inline bin_size_calculator& operator &(bin_size_calculator& calc, unsigned __int64 value)
{
    calc += sizeof(__int64);
    return calc;
}

#endif